<template>
  <PageContainer>
    <h2 style="margin-bottom: 16px">平台监控</h2>
    <el-card style="margin-bottom: 16px;">
      <SearchForm :form-list="searchList" :search-param="searchInfo" @search="handleSearch" @reset="handleReset"  />
    </el-card>

    <el-card style="overflow: auto">
      <!-- <div style="margin-bottom: 10px">
        <el-button type="primary" @click="codeErr">js错误</el-button>
        <el-button type="success" @click="asyncError">异步错误</el-button>
        <el-button type="danger" @click="promiseErr">promise错误</el-button>
        <el-button type="info" @click="xhrError">xhr请求报错</el-button>
        <el-button type="warning" @click="fetchError">fetch请求报错</el-button>
        <el-button type="danger" @click="resourceError">加载资源报错</el-button>
      </div> -->
      <el-table :data="tableData" style="width: 100%">
        <el-table-column type="index" label="序号" width="50"></el-table-column>
        <el-table-column type="expand" label="展开" width="50">
          <template slot-scope="scope">
            <div v-if="['xhr', 'fetch'].includes(scope.row.type)">
              <span>请求参数</span>
              <el-input type="textarea" autosize :value="getRequestData(scope.row.requestData)" />
            </div>
          </template>
        </el-table-column>
        <el-table-column
          v-for="item in columns"
          :key="item.prop"
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :sortable="item.sortable"
        >
          <template slot-scope="scope">
            <template v-if="item.customRender">
              <span>{{ item.customRender(scope.row) }}</span>
            </template>
            <template v-else-if="item.prop === 'action'">
              <!-- <el-button v-if="scope.row.type == 'error' || scope.row.type == 'unhandledrejection'" type="text" size="small" @click="revertCode(scope.row)">
                查看源码
              </el-button> -->
              <el-button
                v-if="scope.row.recordScreenId"
                type="text"
                size="small"
                @click="playRecord(scope.row.recordScreenId)"
              >
                播放录屏
              </el-button>
              <el-button
                v-if="scope.row.breadcrumb"
                type="text"
                size="small"
                @click="revertBehavior(scope.row)"
              >
                查看用户行为
              </el-button>
              <el-button
                type="text"
                size="small"
                @click="handleDelete(scope.row)"
              >
                删除
              </el-button>
            </template>
            <span v-else>{{ scope.row[item.prop] }}</span>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        style="margin-top: 16px; text-align: right"
        :current-page.sync="pagData.pageNum"
        :page-size.sync="pagData.pageSize"
        :total="pagData.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </el-card>

    <el-dialog
      :title="dialogTitle"
      :class="{ 'revert-disalog': fullscreen }"
      top="10vh"
      :fullscreen="fullscreen"
      :visible.sync="revertdialog"
      width="60%"
      :destroy-on-close="true"
    >
      <div id="revert" ref="revert" v-if="dialogTitle != '查看用户行为'"></div>
      <el-timeline v-else>
        <el-timeline-item
          v-for="(activity, index) in activities"
          :key="index"
          :icon="activity.icon"
          :color="activity.color"
          :timestamp="format(activity.time)"
        >
          {{ activity.content }}
        </el-timeline-item>
      </el-timeline>
    </el-dialog>
  </PageContainer>
</template>

<script>
import SearchForm from '../components/SearchForm.vue';
import { findCodeBySourceMap } from "./utils/sourcemap";
import { unzip } from "./utils/recordScreen.js";
import rrwebPlayer from "rrweb-player";
import "rrweb-player/dist/style.css";

const urlPrefix = "http://localhost:8083/api/monitor"

export default {
  name: "HomeView",
  components: {
    SearchForm,
  },
  data() {
    return {
      fullscreen: true,
      revertdialog: false,
      dialogTitle: "",
      activities: [],
      columns: [
        {
          label: "报错类型",
          prop: "type",
          width: "100",
        },
        {
          label: "报错信息",
          prop: "message",
          width: "300",
        },
        {
          label: "报错页面",
          prop: "page_url",
          width: "150",
        },
        {
          label: "报错时间",
          prop: "time",
          width: "150",
          sortable: true,
          customRender: (row) => (row.time ? this.format(row.time) : row.date),
        },
        {
          label: "项目编号",
          prop: "apikey",
        },
        {
          label: "用户id",
          prop: "userId",
        },
        {
          label: "SDK版本",
          prop: "sdkVersion",
        },
        {
          label: "浏览器",
          prop: "browser",
          customRender: (row) => row.deviceInfo?.browser || "-",
        },
        {
          label: "应用系统",
          prop: "os",
          customRender: (row) => row.deviceInfo?.os || "-",
        },
        {
          label: "操作",
          prop: "action",
          width: "220",
        },
      ],
      tableData: [],
      searchList: [
        {
          valueType: "input",
          key: "type",
          label: "报错类型",
        },
        {
          valueType: "input",
          key: "apikey",
          label: "项目编号",
        },
      ],
      searchInfo: {
        type: "",
        apikey: "",
      },
      pagData: {
        pageNum: 1,
        pageSize: 10,
        total: 0,
      },
    };
  },
  created() {
    this.getTableData();
  },
  methods: {
    getTableData() {
      const { pageNum, pageSize } = this.pagData;
      const { type, apikey } = this.searchInfo;
      fetch(
        `${urlPrefix}/getErrorList?pageNum=${pageNum}&pageSize=${pageSize}&type=${type}&apikey=${apikey}`
      )
        .then((response) => response.json())
        .then((res) => {
          const { list, total } = res.data
          this.tableData = list;
          this.pagData.total = total;
        });
    },
    fetchError() {
      fetch("https://jsonplaceholder.typicode.com/posts/a")
        .then((res) => {
          if (res.status == 404) {
            this.getTableData();
          }
        })
        .catch(() => {
          this.getTableData();
        });
    },
    revertBehavior({ breadcrumb }) {
      this.dialogTitle = "查看用户行为";
      this.fullscreen = false;
      this.revertdialog = true;
      if (!Array.isArray(breadcrumb)) return
      breadcrumb.forEach((item) => {
        item.color = item.status == "ok" ? "#5FF713" : "#F70B0B";
        item.icon = item.status == "ok" ? "el-icon-check" : "el-icon-close";
        if (item.category == "Click") {
          item.content = `用户点击dom: ${item.data}`;
        } else if (item.category == "Http") {
          item.content = `调用接口: ${item.data.url}, ${
            item.status == "ok" ? "请求成功" : "请求失败"
          }`;
        } else if (item.category == "Code_Error") {
          item.content = `代码报错：${item.data.message}`;
        } else if (item.category == "Resource_Error") {
          item.content = `加载资源报错：${item.message}`;
        } else if (item.category == "Route") {
          item.content = `路由变化：从 ${item.data.from}页面 切换到 ${item.data.to}页面`;
        }
      });
      // 时间新的在前
      this.activities = breadcrumb.reverse();
    },
    revertCode(row) {
      findCodeBySourceMap(row, (res) => {
        this.dialogTitle = "查看源码";
        this.fullscreen = false;
        this.revertdialog = true;
        this.$nextTick(() => {
          this.$refs.revert.innerHTML = res;
        });
      });
    },
    playRecord(id) {
      fetch(`${urlPrefix}/getRecordScreenId?id=${id}`)
        .then((response) => response.json())
        .then((res) => {
          let { code, data } = res;
          if (code == 200 && Array.isArray(data) && data[0]?.events) {
            let events = unzip(data[0].events);
            this.fullscreen = true;
            this.dialogTitle = "播放录屏";
            this.revertdialog = true;
            this.$nextTick(() => {
              new rrwebPlayer(
                {
                  target: document.getElementById("revert"),
                  data: {
                    events,
                  },
                },
                {
                  UNSAFE_replayCanvas: true,
                }
              );
            });
          }
        });
    },
    format(time) {
      let str = new Date(time);
      return (
        str.toLocaleDateString().replace(/\//g, "-") +
        " " +
        str.toTimeString().substr(0, 8)
      );
    },
    asyncError() {
      this.getTableData();
      setTimeout(() => {
        JSON.parse("");
      });
    },
    codeErr() {
      this.getTableData();
      let a = undefined;
      if (a.length) {
        console.log("1");
      }
    },
    resourceError() {
      let script = document.createElement("script");
      script.type = "text/javascript";
      script.src = "https://abc.com/index.js";
      document.body.appendChild(script);
      // 资源加载失败
      script.onerror = () => {
        this.getTableData();
      };
    },
    promiseErr() {
      new Promise((resolve) => {
        this.getTableData();
        let person = {};
        person.name.age();
        resolve();
      });
    },
    xhrError() {
      let _this = this;
      let ajax = new XMLHttpRequest();
      ajax.open("GET", "https://abc.com/test/api");
      ajax.setRequestHeader("content-type", "application/json");
      ajax.onreadystatechange = function () {
        if (ajax.readyState == 4) {
          _this.getTableData();
        }
        if (ajax.status === 200 || ajax.status === 304) {
          console.log("ajax", ajax);
        }
      };
      ajax.send();
      ajax.addEventListener("loadend", () => {});
    },
    getRequestData(value) {
      return value ? value.data : ""
    },
    //
    handleSearch() {
      this.pagData.pageNum = 1
      this.getTableData()
    },
    handleReset() {
      this.searchInfo = Object.assign({}, this.$options.data().searchInfo)
    },
    // 分页查询
    handleCurrentChange(pageNum) {
      this.pagData.pageNum = pageNum;
      this.getTableData();
    },
    handleSizeChange(pageSize) {
      this.pagData.pageSize = pageSize;
      this.pagData.pageNum = 1;
      this.getTableData();
    },
    handleDelete(row) {
      console.log('删除: ', row);
      this.$confirm("确定删除所选项吗？", "提示")
      .then(async () => {
        fetch(`${urlPrefix}/error-item/${row.id}`, {
          method: 'delete',
        })
        .then((response) => response.json())
        .then((res) => {
          if (res.code === 200) {
            this.getTableData();
            // 删除录屏
            fetch(`${urlPrefix}/screen-item/${row.recordScreenId}`, {
              method: 'delete',
            })
          }
        });
      })
      .catch(() => {
      })
    },
  },
};
</script>

<style lang="scss">
.el-dialog__header {
  font-size: 20px;
  font-weight: 800;
}
.el-dialog__body {
  padding: 16px;
  max-height: 70vh;
  overflow: auto;
}

.el-timeline {
  text-align: left;
  .el-timeline-item__icon {
    font-size: 12px;
  }
}
.revert-disalog {
  .el-dialog__body {
    height: 720px;
  }
}
.rr-player {
  margin: 0 auto;
}
#revert {
  width: 100%;
  display: flex;
}
.errdetail {
  text-align: left;
  width: 100%;
  font-size: 16px;
}
.code-line {
  padding: 5px 0;
}
.heightlight {
  background-color: yellowgreen;
}
.errheader {
  padding: 10px;
  border-bottom: 1px solid rgb(214, 210, 210);
}

.filter-item {
  display: flex;
  align-items: center;
  margin-right: 20px;

  >span {
    display: inline-block;
    width: 100px;
    margin-right: 5px;

  }
}

.buttons {
  margin-left: 30px;
  display: flex;
  width: 180px;
}
</style>